using System;
using System.Linq;

using TrueCode.DependencyManager;
using TrueCode.DependencyManager.Interface;

namespace EMan.Common.DependencyInjection
{
  public class SessionalParameterBuildAction : IGetSessionalParameter
  {
    private readonly object[] myParameters;

    public SessionalParameterBuildAction(object[] parameters)
    {
      if (parameters.Length == 0) throw new ArgumentNullException("parameters", @"No parameters specified");
      myParameters = parameters;
    }

    public void Execute(IBuildSession context)
    {
      var value = GetValue(context.SessionAim.Type);
      if(value != null)
        context.Instance = value;
      else
        context.ExecuteNextBuildAction();
    }

    private object GetValue( Type requestedType )
    {
      var parameters = myParameters.
        Where( param =>
          {
            var typedValue = param as TypedValue;
            return typedValue == null
                     ? requestedType.IsAssignableFrom( param.GetType() )
                     : typedValue.Type == requestedType;
          } ).
        Select( param =>
          {
            var typedValue = param as TypedValue;
            return typedValue == null ? param : typedValue.Value;
          } );

      #region Assert that there is no parameters abmbiguity
      if( parameters.Count() > 1 )
      {
        var exception = new InvalidOperationException( "Parameters ambiguity, more than one parameter is assignable to requested type" );
        exception.Data.Add( "Type of method parameter", requestedType );

        var counter = 0;
        foreach( var parameter in parameters )
          exception.Data.Add( "Proper parameter type" + counter++, parameter.GetType() );
        throw exception;
      }
      #endregion

      return parameters.FirstOrDefault();
    }
  }
}